home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch14 / blobgui.c next >
C/C++ Source or Header  |  1994-09-14  |  63KB  |  2,436 lines

  1. /*
  2. -----------------------------------------------------------------------------
  3.  BLOB MODELER
  4.  By Alfonso Hermida and Steve Anger  Dates: 12/16/93 ~ 2/15/94
  5.  
  6. -----------------------------------------------------------------------------
  7. */
  8.  
  9. #include <dos.h>
  10. #include <graphics.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <conio.h>
  15. #include <math.h>
  16. #include <ctype.h>
  17.  
  18. #define TOL 0.0005
  19. #define PI  3.14159265358979323846
  20.  
  21. #define FULLSCREEN_VIEW setviewport(0,0,getmaxx(),getmaxy(),1);
  22.  
  23. #define FRONT_ID 0
  24. #define SIDE_ID  1
  25. #define TOP_ID   2
  26. #define ISO_ID   3
  27.  
  28. #define FRONT_VIEW setviewport(1, 241, 239, 478, 1);
  29. #define SIDE_VIEW  setviewport(241, 241, 478, 478,1);
  30. #define TOP_VIEW   setviewport(1, 1, 239, 239, 1);
  31. #define ISO_VIEW   setviewport(241, 1, 478, 239, 1);
  32.  
  33. #define FRONT_AREA  0
  34. #define SIDE_AREA   1
  35. #define TOP_AREA    2
  36. #define ISO_AREA    3
  37. #define MENU_AREA   4
  38.  
  39. #define TEXT_INPUT   1
  40. #define NUMBER_INPUT 0
  41.  
  42. #define UP   1
  43. #define DOWN 0
  44.  
  45. typedef struct {
  46.   int x,y,width,height;
  47.   int color;
  48.   char str[81];
  49. } Icon;
  50.  
  51. typedef struct {
  52.  float x,y,z;
  53. } POINT3D;
  54.  
  55. typedef struct {
  56.  int x,y;
  57. } POINTint;
  58.  
  59. typedef struct {
  60.  POINT3D from, up, at;
  61.  float angle;
  62. }Window3D;
  63.  
  64. typedef struct {
  65.   float Hmin, Vmin, Hmax, Vmax;
  66. }WorldLimits;
  67.  
  68. typedef struct {
  69.  float x,y,z;
  70.  float radius, strength;
  71. } BLOB;
  72.  
  73. typedef struct {
  74.   POINT3D p1, p2;
  75. } PAIR3D;
  76.  
  77.  
  78. typedef struct {
  79.     float value;
  80.     POINT3D loc;
  81. } SAMPLE;
  82.  
  83. typedef struct {
  84.    float rmin, cmin,
  85.          rowstep,colstep,
  86.          PlaneDist;
  87.    int rows, cols;
  88.    char PerpTo;
  89. } GRID;
  90.  
  91.  
  92. // MOUSE ROUTINES
  93. int IsMouse (void);
  94. int MouseClick (void);
  95. void MouseXY (int *xpos, int *ypos);
  96. void MouseShow (int toggle);
  97. int WhereIsMouse(int x, int y);
  98. void UpdateMousePos(int xpos,int ypos,int status);
  99.  
  100. // ICON ROUTINES
  101. Icon CreateIcon(int xo,int yo,int width,int height,int color,char * text);
  102. void DrawIcon (Icon ic);
  103. int IconCheck (Icon ikon, int xm, int ym);
  104. void DrawIconHiLite(Icon ic, int UpDown);
  105. void CreateIconColumn (int xo, int yo, int width, int height, int color, int
  106.      spc, int num, Icon icon[], char **text);
  107. void CreateIconRow(int xo,int yo,int width,int height,int color,
  108.            int spc, int num, Icon icon[],char **text);
  109.  
  110. // WINDOW ROUTINES
  111. void InitGraphics(void);
  112. void SetWindow3D(int vp, int size);
  113. void SetViewpoint(void);
  114. void clearWindow(int vp);
  115. void WorldToDevice(double xw, double yw, int *xpc, int *ypc);
  116. void ScreenToWorld(int mx, int my, float *wx, float *wy);
  117. void World2DToDevice(POINT3D pp,int *xd, int *yd);
  118. POINTint World3DToDevice(POINT3D v1);
  119. void GetGridPoint2D(GRID g, int mx,int my, float * wx, float * wy);
  120. POINT3D GetPoint3D(int mx, int my);
  121.  
  122.  
  123. // 3D DRAWING ROUTINES
  124. void drawpoint3D(POINT3D *v1);
  125. void drawline3D(POINT3D *v1, POINT3D *v2);
  126. void DrawAxes(void);
  127. void drawsphere (int WinNum, POINT3D pc,float R);
  128.  
  129.  
  130. // VECTOR ROUTINES
  131. POINT3D add(POINT3D *a,POINT3D *b);
  132. POINT3D subtract(POINT3D *at,POINT3D *from);
  133. float mag(POINT3D *v);
  134. int equal(POINT3D *a, POINT3D *b);
  135. POINT3D multiply(POINT3D *v,float f);
  136. POINT3D divide(POINT3D *v,float d);
  137. POINT3D cross(POINT3D *v1, POINT3D *v2);
  138.  
  139.  
  140. // MISCELLANEOUS ROUTINES
  141. float DegToRad(float deg);
  142. void AllocateInputBox(void);
  143. void EraseInputBox(void);
  144. char * InputBox(char *s);
  145. char* KeyInput(char* str,int text);
  146. char* prompt (int x,int y);
  147. int YesNoCMD(char *s);
  148. void InfoBox(char *s);
  149.  
  150.  
  151. // BLOB ROUTINES
  152. float BlobFunc (POINT3D p);
  153. int AllocateCubes (void);
  154. void FreeCubes (void);
  155. void SampleLevel (SAMPLE **level, int ix, POINT3D *vmin, POINT3D *vmax);
  156. int CreateBlobs (void);
  157. void CubeIntersect (int iy, int iz);
  158. void FaceIntersect (SAMPLE *cube, int a, int b, int c, int d, PAIR3D *line, int *
  159.     numline);
  160. void EdgeIntersect (POINT3D *v, SAMPLE *a, SAMPLE *b);
  161. void DrawBlobs(BLOB b, int vp);
  162.  
  163.  
  164. // MENU COMMANDS
  165. void ExecCommand(int c, int mx, int my, int use_xy, int btnprss);
  166. void CreateABlob(int mx, int my, int use_xy, int btn);
  167. void SelectABlob(int mx, int my, int use_xy, int btn);
  168. void CenterAView(int mx, int my, int use_xy, int btn);
  169. void Zoom(int mx, int my, int use_xy, int btn);
  170. void MoveABlob(int mx, int my, int use_xy, int btn, int copy);
  171. void WriteToPolyray(void);
  172. void WriteToPoV(void);
  173. void DeleteBlob(int mx, int my, int use_xy, int btn);
  174. void LoadAFile(char *str);
  175. void SaveAFile(char *str);
  176. void RedrawALL(void);
  177. void SetStrength(int mx, int my, int use_xy, int btn);
  178. void SetCamera(void);
  179. void ResizeABlob(int mx, int my, int use_xy, int btn);
  180. void drawgrid (int cw, GRID g);
  181.  
  182.  
  183. //----------------
  184. union REGS inregs;    // mouse related
  185. union REGS outregs;   // mouse related
  186.  
  187.  
  188. extern unsigned _stklen = 8000;
  189.  
  190. // Global Info For Drawing
  191. POINT3D from, up, at;              //viewing parameters
  192. POINT3D a1, a2, a3;                //used in transforming coordinates
  193. int DeviceBottom, DeviceTop,       //boundaries of viewing area
  194.     DeviceLeft, DeviceRight;
  195. float a, b, c, d, DVal;
  196. float angle;                        //viewing angle
  197. float offset_x, offset_y, offset_z; //transform variables
  198. int ViewPort;                      // Current Selected ViewPort
  199. int BlobSel = 0;                   // selected blob
  200. int BlobSelOld = 0;
  201. int SaveRAW = 0;                   // RAW
  202. WorldLimits World[3];
  203. char FileName[80];                 // current file loaded
  204. FILE *RAWfptr;                     // for saving RAW data faster
  205.  
  206. float threshold = 0.6;
  207. int bnum = 0;                      // number of blobs
  208.  
  209. #define MAXBLOB 500
  210. BLOB blobs[MAXBLOB+1];
  211. int LastCMD = -1;                  // last command select
  212. void  *BitMap;
  213.  
  214. GRID grid[3];                        // grids for 3 views
  215. int GridRowCol = 20;                 // divisions on grid
  216. int GridStatus = 0;                  // show grid?
  217. int SnapStatus = 0;                  // show grid/snap?
  218.  
  219. SAMPLE **level0 = NULL;
  220. SAMPLE **level1 = NULL;
  221. int x_steps = 30;
  222. int y_steps = 30;
  223. int z_steps = 30;
  224. int hide_backface = 1;  /* 0 = see through, 1 = front faces only */
  225.  
  226. #define IconNum  25
  227. //---------------------------------------------------------------------
  228. void main(void)
  229. {
  230.  int i, mx, my, mxold = -1, myold = -1, status, status2, btn=0 ;
  231.  Icon icon[IconNum];
  232.   #define KLR LIGHTBLUE
  233.   icon[2] =   CreateIcon(483,  3,72,15,KLR," Create");
  234.   icon[4] =  CreateIcon(483,  21,72,15,KLR," Resize");
  235.   icon[3] =  CreateIcon(483, 39,72,15,KLR,"  Move");
  236.   icon[24] = CreateIcon(483, 57,72,15,KLR,"  Copy");
  237.   icon[9] =  CreateIcon(483, 75,72,15,KLR," Delete");
  238.   icon[13] = CreateIcon(483, 93,72,15,KLR," Density");
  239.   #undef KLR
  240.  
  241.  #define KLR CYAN
  242.  icon[0] = CreateIcon(560,  3,72,15,KLR,"  Load");
  243.   icon[18] = CreateIcon(560,  21,72,15,KLR,"  New");
  244.  icon[1] = CreateIcon(560, 39,72,15,KLR,"  Save");
  245.  icon[5] = CreateIcon(560, 57,72,15,KLR," Povray");
  246.  icon[6] = CreateIcon(560, 75,72,15,KLR," Polyray");
  247.  icon[7] = CreateIcon(560, 93,72,15,KLR,"   RAW");
  248.  #undef KLR
  249.  
  250.   #define KLR CYAN
  251.   icon[16] = CreateIcon(483, 129,72,15,KLR," Redraw");
  252.   icon[10] = CreateIcon(483, 147,72,15,KLR,"   Pan");
  253.   icon[23] = CreateIcon(483, 165,72,15,KLR," Origin");
  254.   icon[8] = CreateIcon(483, 183,72,15,KLR,"  Zoom");
  255.  
  256.   #undef KLR
  257.  
  258.  #define KLR LIGHTBLUE
  259.   icon[20] = CreateIcon(560, 129,72,15,KLR,"  Snap");
  260.   icon[21] = CreateIcon(560, 147,72,15,KLR,"  Grid");
  261.   icon[22] = CreateIcon(560, 165,72,15,KLR," Row/Col");
  262.  #undef KLR
  263.  
  264.  #define KLR RED
  265.  icon[19] = CreateIcon(515, 288,100,15,KLR," Threshold");
  266.  icon[12] = CreateIcon(483, 306,72,15,KLR," Preview");
  267.  icon[17] = CreateIcon(560, 306,72,15,KLR," Detail");
  268.  icon[11] = CreateIcon(515, 324,100,15,KLR,"   Camera");
  269.  #undef KLR
  270.  
  271.  icon[14] = CreateIcon(500, 450,72,15,7," Quit");
  272.  icon[15] = CreateIcon(580, 450,40,15,7," Who");
  273.  
  274.  
  275.  // FRONT DEFAULT VALUES
  276.  World[0].Hmin = -2;
  277.  World[0].Vmin = -2;
  278.  World[0].Hmax = 2;
  279.  World[0].Vmax = 2;
  280.  // SIDE DEFAULT VALUES
  281.  World[1].Hmin = -2;
  282.  World[1].Vmin = -2;
  283.  World[1].Hmax = 2;
  284.  World[1].Vmax = 2;
  285.  // TOP DEFAULT VALUES
  286.  World[2].Hmin = -2;
  287.  World[2].Vmin = -2;
  288.  World[2].Hmax = 2;
  289.  World[2].Vmax = 2;
  290.  // ISO DEFAULT VALUES
  291.  from.x = 1; from.y = 1;  from.z = -2.5;
  292.  at.x = 0;  at.y = 0;  at.z = 0;
  293.  up.x = 0;  up.y = 1;  up.z = 0;
  294.  angle = DegToRad(45);
  295.  
  296.  
  297.  
  298.  InitGraphics();
  299.  if (!IsMouse()) {
  300.     closegraph(); printf("MOUSE driver not installed!"); exit(1);
  301.  }
  302.  setcolor(7);
  303.  rectangle(0,0,getmaxy(),getmaxy());
  304.  line(1,240,getmaxy(),240);
  305.  line(240,1,240,getmaxy());
  306.  setcolor(15);
  307.  setfillstyle(1, 7);
  308.  bar3d(481,0,getmaxx(),getmaxy(),0,0);
  309.  for(i=0;i<IconNum;i++)  DrawIcon(icon[i]);
  310.  setcolor(15);
  311.  setfillstyle(1, 15);
  312.  bar3d(530,260,610,275,0,0);
  313.  setcolor(0);
  314.  outtextxy(531, 262, "SNAP OFF");
  315.  outtextxy(490, 355, "Blob Sculptor 1.0a");
  316.  setcolor(WHITE);
  317.  outtextxy(491, 356, "Blob Sculptor 1.0a");
  318.  
  319.  strcpy(FileName,"");
  320.  RedrawALL();
  321.  status = 0;
  322.  setcolor(WHITE);
  323.  MouseShow(1);
  324.  do {
  325.    do {MouseXY (&mx, &my);
  326.      if((mx != mxold) || (my != myold)) {
  327.          UpdateMousePos(mx,my,0);
  328.      mxold = mx;
  329.          myold = my;
  330.      }
  331.      btn = MouseClick();
  332.    }while(!btn);
  333.  
  334.    for (i=0;i<IconNum;i++) {
  335.       status = IconCheck(icon[i],mx,my);
  336.       if (status) {
  337.          DrawIconHiLite(icon[i], DOWN);
  338.          if (LastCMD > -1) DrawIconHiLite(icon[LastCMD],UP);
  339.          if (i == 14) {
  340.             status = 14;
  341.             break;
  342.          }
  343.          else {
  344.           LastCMD = i;
  345.           ExecCommand(i, mx, my, 0, btn);
  346.          }
  347.       }
  348.    }
  349.    if (!status) {   // If an icon command wasn't executed
  350.       status2 = WhereIsMouse(mx,my);
  351.       if ((status2 == FRONT_AREA) ||
  352.           (status2 == SIDE_AREA) ||
  353.           (status2 == TOP_AREA) ||
  354.           (status2 == ISO_AREA)) ExecCommand(LastCMD, mx, my, 1, btn);
  355.    }
  356.    if ((LastCMD == 0) ||
  357.        (LastCMD == 1) ||
  358.        (LastCMD == 5) ||
  359.        (LastCMD == 6) ||
  360.        (LastCMD == 7) ||
  361.        (LastCMD == 12) ||
  362.        ((LastCMD > 13) && (LastCMD <= 22))) {
  363.              FULLSCREEN_VIEW
  364.              delay(50);
  365.              DrawIconHiLite(icon[LastCMD],UP);
  366.              LastCMD = -1;
  367.    }
  368.   }while(status != 14);
  369.   closegraph();
  370.   exit(1);
  371.  
  372. }
  373. /////////////////////////////////////////////////////////////////////
  374.  
  375. void UpdateGridStatus(int vp)
  376. {
  377.   grid[vp].rmin = World[vp].Vmin;
  378.   grid[vp].cmin = World[vp].Hmin;
  379.   grid[vp].rowstep = (fabs(World[vp].Vmin)+ fabs(World[vp].Vmax)) / (1.0 * GridRowCol);
  380.   grid[vp].colstep = (fabs(World[vp].Hmin)+ fabs(World[vp].Hmax)) / (1.0 * GridRowCol);
  381.   grid[vp].PlaneDist = 0.0;
  382.   grid[vp].rows = GridRowCol;
  383.   grid[vp].cols = GridRowCol;
  384.   switch(vp) {
  385.    case 0: grid[vp].PerpTo = 'Z';break;
  386.    case 1: grid[vp].PerpTo = 'X';break;
  387.    case 2: grid[vp].PerpTo = 'Y';break;
  388.    case 3: grid[vp].PerpTo = 'Z';break;
  389.   }
  390. }
  391.  
  392. void CreateIconRow(int xo,int yo,int width,int height,int color,
  393.                    int spc, int num, Icon icon[],char **text)
  394. {
  395.  int i,x;
  396.  x = xo;
  397.  for(i=0;i<num;i++) {
  398.    icon[i] = CreateIcon(x,yo,width,height,color,text[i]);
  399.    x += width + spc;
  400.  }
  401. }
  402.  
  403. int YesNoCMD(char *s)
  404. {
  405.  char *str[2] = {" Yes"," No"};
  406.  Icon icon[2];
  407.  int i,xpos,ypos,status,choice = 0;
  408.  
  409.  CreateIconRow(180,200,55,15,LIGHTGRAY,60,2,icon,str);
  410.  MouseShow(0);
  411.  FULLSCREEN_VIEW
  412.  setfillstyle(1,LIGHTGRAY);
  413.  bar3d(150,150,400,220,0,0);
  414.  for(i=0;i<2;i++) DrawIcon(icon[i]);
  415.  setcolor(0);
  416.  outtextxy(160,160,s);
  417.  MouseShow(1);
  418.  do {MouseXY(&xpos, &ypos); }while(!MouseClick());
  419.  
  420.  for(i=0;i<2;i++) {
  421.    status = IconCheck(icon[i],xpos,ypos);
  422.    if (status) {
  423.     switch(i) {
  424.      case 0: choice = 1;break;
  425.      case 1: choice = 0;break;
  426.     }
  427.    }
  428.  }
  429.  return(choice);
  430. }
  431.  
  432.  
  433. void InfoBox(char *s)
  434. {
  435.  int xpos,ypos;
  436.  MouseShow(0);
  437.  FULLSCREEN_VIEW
  438.  setfillstyle(1,LIGHTGRAY);
  439.  bar3d(100,100,120 + strlen(s) * textwidth("W") ,100 + 6 * textheight("W"),0,0);
  440.  setcolor(0);
  441.  outtextxy(110,110,s);
  442.  MouseShow(1);
  443.  do {MouseXY(&xpos, &ypos); }while(!MouseClick());
  444. }
  445.  
  446.  
  447. void ResizeABlob(int mx, int my, int use_xy, int btn)
  448. {
  449.  int i, mxold=0, myold=0;
  450.  POINT3D p1, p2, v;
  451.  BLOB tmp, tmpold;
  452.  
  453.  SelectABlob(mx, my, use_xy, btn);
  454.  if (BlobSel) {
  455.   tmp = blobs[BlobSel];
  456.   tmpold = tmp;
  457.   p1.x = tmp.x; p1.y = tmp.y; p1.z = tmp.z;
  458.   setcolor(WHITE);
  459.   MouseShow(0);
  460.   for(i=0;i<4;i++) {
  461.      SetWindow3D(i,0);
  462.      DrawBlobs(blobs[BlobSel],i);
  463.   }
  464.   MouseShow(1);
  465.   do {MouseXY (&mx, &my);
  466.      if((mx != mxold) || (my != myold)) {
  467.          UpdateMousePos(mx,my,0);
  468.      mxold = mx;
  469.          myold = my;
  470.      }
  471.      p2 = GetPoint3D(mx,my);
  472.      v = subtract(&p2, &p1);
  473.  
  474.      tmp.radius = mag(&v)/sqrt(1.0 - sqrt(threshold/fabs(tmp.strength)));
  475.  
  476.      MouseShow(0);
  477.      setwritemode(1);
  478.      setcolor(WHITE);
  479.      for(i=0;i<3;i++) {
  480.       SetWindow3D(i,0);
  481.       DrawBlobs(tmpold,i);
  482.       DrawBlobs(tmp,i);
  483.      }
  484.      setwritemode(0);
  485.      MouseShow(1);
  486.      tmpold = tmp;
  487.      btn = MouseClick();
  488.   }while(!btn);
  489.   if (btn == 1) blobs[BlobSel]  = tmp;
  490.   RedrawALL();
  491.  }
  492. }
  493.  
  494.  
  495. void SetCamera(void)
  496. {
  497.  int i,j,c,ok = 0,xpos,ypos;
  498.  char  *str[11] = {" From X", " From Y", " From Z",
  499.                    " To   X", " To   Y", " To   Z",
  500.                    " Up   X", " Up   Y", " Up   Z",
  501.                    "   OK   ", " Cancel "};
  502.  Icon Col[11];
  503.  char terms[9][80], s[80], s2[40];
  504.    FULLSCREEN_VIEW
  505.    MouseShow(0);
  506.    CreateIconColumn(75,100,60,15,LIGHTGRAY,5,11,Col,str);
  507.    for(i=9;i<11;i++) {
  508.     Col[i].x = Col[i-9].x + 300;
  509.     Col[i].y = Col[i-9].y;
  510.    }
  511.    sprintf(s2,"%g",from.x);  strcpy(terms[0],s2);
  512.    sprintf(s2,"%g",from.y);  strcpy(terms[1],s2);
  513.    sprintf(s2,"%g",from.z);  strcpy(terms[2],s2);
  514.    sprintf(s2,"%g",  at.x);  strcpy(terms[3],s2);
  515.    sprintf(s2,"%g",  at.y);  strcpy(terms[4],s2);
  516.    sprintf(s2,"%g",  at.z);  strcpy(terms[5],s2);
  517.    sprintf(s2,"%g",  up.x);  strcpy(terms[6],s2);
  518.    sprintf(s2,"%g",  up.y);  strcpy(terms[7],s2);
  519.    sprintf(s2,"%g",  up.z);  strcpy(terms[8],s2);
  520.  
  521.    setcolor(0);
  522.    setfillstyle(1,LIGHTGRAY);
  523.    bar3d(60,85,Col[9].x + 70,Col[8].y + 30,0,0);
  524.    for(i=0;i<11;i++) DrawIcon(Col[i]);
  525.    outtextxy((Col[9].x + 10)/2 + 60,88,"CAMERA");
  526.    MouseShow(1);
  527.    do {
  528.     MouseShow(0);
  529.     setcolor(LIGHTGRAY);
  530.     setfillstyle(1,LIGHTGRAY);
  531.     bar3d(Col[0].x+62,Col[0].y,Col[9].x - 2,Col[8].y + 15,0,0);
  532.  
  533.     setcolor(0);
  534.     for(c=0;c<9;c++)  outtextxy(Col[c].x + 70,Col[c].y + 3,terms[c]);
  535.  
  536.     MouseShow(1);
  537.     do { MouseXY(&xpos, &ypos);
  538.     }while(!MouseClick());
  539.     for(i=0;i<11;i++) {
  540.        j = IconCheck(Col[i],xpos,ypos);
  541.        if (j) {
  542.          if ((i>=0) && (i<=8)) {
  543.      MouseShow(0);
  544.            strcpy(s,KeyInput(Col[i].str,NUMBER_INPUT));
  545.      MouseShow(1);
  546.            if (strlen(s)) strcpy(terms[i],s);
  547.          }
  548.      else {
  549.            if (i==9)  ok =  1;
  550.            if (i==10) ok = -1;
  551.          }
  552.        }
  553.     }
  554.    }while(ok == 0);
  555.  
  556.    if (ok == 1) {
  557.      from.x = atof(terms[0]); from.y = atof(terms[1]); from.z = atof(terms[2]);
  558.        at.x = atof(terms[3]);   at.y = atof(terms[4]);   at.z = atof(terms[5]);
  559.        up.x = atof(terms[6]);   up.y = atof(terms[7]);   up.z = atof(terms[8]);
  560.    }
  561.    RedrawALL();
  562. }
  563.  
  564.  
  565. void SetStrength(int mx, int my, int use_xy, int btn)
  566. {
  567.  char str[80],pstr[80];
  568.   SelectABlob(mx,my,use_xy,btn);
  569.   FULLSCREEN_VIEW
  570.   if (BlobSel) {
  571.     sprintf(pstr,"Strength: [%g]",blobs[BlobSel].strength);
  572.     strcpy(str,KeyInput(pstr,NUMBER_INPUT));
  573.     if (strcmp(str,"")) blobs[BlobSel].strength = atof(str);
  574.   }
  575. }
  576.  
  577.  
  578. void RedrawALL(void)
  579. {
  580.  int i,j;
  581.   FULLSCREEN_VIEW
  582.   MouseShow(0);
  583.   setcolor(7);
  584.   rectangle(0,0,getmaxy(),getmaxy());
  585.   line(1,240,getmaxy(),240);
  586.   line(240,1,240,getmaxy());
  587.   setcolor(WHITE);
  588.   for (i=0;i<4;i++) {
  589.      SetWindow3D(i,0);
  590.      clearviewport();
  591.      UpdateGridStatus(i);            // must be updated ALWAYS!
  592.      if (GridStatus && (i < 3)) {
  593.       setcolor(LIGHTGRAY);
  594.       drawgrid(i,grid[i]);
  595.      }
  596.      DrawAxes();
  597.      setcolor(WHITE);
  598.      if (bnum) {
  599.          for(j=1;j<=bnum;j++) {
  600.             if (blobs[j].strength < 0) setcolor(LIGHTRED);
  601.             else setcolor(WHITE);
  602.             DrawBlobs(blobs[j],i);
  603.  
  604.          }
  605.      }
  606.   }
  607.  setcolor(WHITE);
  608.  MouseShow(1);
  609. }
  610.  
  611.  
  612. void AllocateInputBox(void)
  613. {
  614.  unsigned size;
  615.  size = imagesize(200,200,500,300);
  616.  if ((BitMap = (void *)malloc(size)) == NULL)
  617.  {
  618.   printf("Not enough memory to allocate buffer!\n");
  619.   exit(1);
  620.  }
  621.  MouseShow(0);
  622.  getimage(200,200,500,300,BitMap);
  623.  MouseShow(1);
  624. }
  625.  
  626.  
  627. void EraseInputBox(void)
  628. {
  629.  MouseShow(0);
  630.  putimage(200,200,BitMap,COPY_PUT);
  631.  free(BitMap);
  632.  MouseShow(1);
  633. }
  634.  
  635.  
  636. char * InputBox(char *s)
  637. {
  638.  static char ans[80];
  639.  MouseShow(0);
  640.  AllocateInputBox();
  641.  setfillstyle(1,LIGHTGRAY);
  642.  bar3d(200,200,500,300,0,0);
  643.  setcolor(15);
  644.  rectangle(200,200,500,300);
  645.  rectangle(205,300-2*textheight("W")-5,495,295);
  646.  setcolor(0);
  647.  outtextxy(205,205,s);
  648.  MouseShow(1);
  649.  strcpy(ans,prompt(207,300-2*textheight("W")-3));
  650.  MouseShow(0);
  651.  EraseInputBox();
  652.  MouseShow(1);
  653.  return(ans);
  654. }
  655.  
  656.  
  657. char* KeyInput(char* str,int text)
  658. {
  659.   static char str1[80];
  660.   int i,error;
  661.  
  662.   do
  663.   {
  664.     error = 0;
  665.     strcpy(str1,InputBox(str));
  666.     if (text==0)
  667.     {
  668.     for (i=0;i<strlen(str1);i++)
  669.       if ((!isdigit(str1[i])) && (str1[i] != '.')
  670.          && (toupper(str1[i]) != 'E') && (str1[i] != '-'))
  671.          error = 1;
  672.     }
  673.     else  {
  674.            for (i=0;i<strlen(str1);i++)
  675.              if (str1[i] == ' ') error = 1;
  676.       }
  677.   }while(error);
  678.   return (str1);
  679. }
  680.  
  681. char* prompt (int x,int y)
  682. {
  683.   char KeyChar,key[2];
  684.   static char word[80];
  685.   int j, erase, stop,TW = textwidth("W"),TH = textheight("W")+1;
  686.   j = 0;
  687.   setcolor(0);
  688.   erase = stop = 0;
  689.   key[1] = '\0';
  690.   do
  691.     {
  692.     KeyChar =  getch();
  693.     key[0] = KeyChar;
  694.     if (KeyChar == 13) stop = 1;
  695.     if ((KeyChar == 8) && (j > 0)) erase = 1;
  696.     if (KeyChar == 0) {
  697.       KeyChar = getch();
  698.       if (((KeyChar == 75) || (KeyChar == 83)) && (j > 0)) erase = 1;
  699.     }
  700.     if (stop) word[j] = '\0';
  701.     else
  702.          if (erase) {
  703.            if (j) {
  704.              j --;
  705.          MouseShow(0);
  706.              bar(x+TW*j,y,x+TW*(j+2),y+TH);
  707.              outtextxy(x+TW*j,y,"_");
  708.          MouseShow(1);
  709.            }
  710.            erase = 0;
  711.          }
  712.          else  {
  713.           if(j<34) {
  714.        MouseShow(0);
  715.            bar(x+TW*j,y,x+TW*(j+2),y+TH);
  716.            outtextxy(x+TW*j,y,key);
  717.            outtextxy(x+TW*(j+1),y,"_");
  718.        MouseShow(1);
  719.            word[j] = key[0];
  720.            j++;
  721.           }
  722.          }
  723.     }while(!stop);
  724.  
  725.   return(word);
  726. }
  727.  
  728.  
  729. void LoadAFile(char *str)
  730. {
  731.  FILE *fptr;
  732.  float x,y,z,r,s;
  733.  if (  (fptr = fopen(str,"r")) == NULL) {
  734.              InfoBox("Can't load the file!");
  735.              RedrawALL();
  736.  }
  737.  else {
  738.      bnum = 0;
  739.      fscanf(fptr,"%f",&threshold);
  740.      while (!feof(fptr)) {
  741.          if ((fscanf(fptr,"%f",&x) > 0) &&
  742.              (fscanf(fptr,"%f",&y) > 0) &&
  743.              (fscanf(fptr,"%f",&z) > 0) &&
  744.              (fscanf(fptr,"%f",&s) > 0) &&
  745.              (fscanf(fptr,"%f",&r) > 0) &&
  746.              (r > TOL) &&
  747.              (bnum < MAXBLOB)) {
  748.           bnum++;
  749.                   blobs[bnum].x = x;
  750.                   blobs[bnum].y = y;
  751.                   blobs[bnum].z = z;
  752.                   blobs[bnum].radius = r;
  753.                   blobs[bnum].strength = s;
  754.          }
  755.      }
  756.      fclose(fptr);
  757.      strcpy(FileName,str);
  758.  }
  759. }
  760.  
  761. void SaveAFile(char *str)
  762. {
  763.  FILE *fptr;
  764.  int i=1;
  765.  char s[40];
  766.  sprintf(s,"Overwrite < %s > ?",str);
  767.  if ((fptr = fopen(str,"r")) != NULL) i = YesNoCMD(s);
  768.  fclose(fptr);
  769.  if (i) {
  770.      if ((fptr = fopen(str,"w+t")) == NULL) {
  771.           InfoBox("Can't open the file for output!");
  772.           RedrawALL();
  773.  
  774.      }
  775.      else {
  776.        if(bnum) {
  777.         MouseShow(0);
  778.             fprintf(fptr,"%g\n",threshold);
  779.             for(i=1;i<=bnum;i++)
  780.                 if (blobs[i].radius > TOL)
  781.                   fprintf(fptr,"%g %g %g %g %g\n",blobs[i].x,blobs[i].y,blobs[i].z,
  782.                                                   blobs[i].strength,blobs[i].radius);
  783.             fclose(fptr);
  784.         MouseShow(1);
  785.        }
  786.      }
  787.  }
  788.  RedrawALL();
  789. }
  790.  
  791.  
  792.  
  793. void DeleteBlob(int mx, int my, int use_xy, int btn)
  794. {
  795.  int i;
  796.  SelectABlob(mx, my, use_xy, btn);
  797.  if (BlobSel) {
  798.   if (YesNoCMD("Delete Blob?")) {
  799.    if (BlobSel && bnum ) {
  800.      if (BlobSel == bnum)
  801.        bnum--;
  802.      else {
  803.        for(i = BlobSel; i<bnum; i++) blobs[i] = blobs[i+1];
  804.        bnum--;
  805.      }
  806.    }
  807.   }
  808.   RedrawALL();
  809.  }
  810. }
  811.  
  812. void WriteToPoV(void)
  813. {
  814.  FILE *fptr;
  815.  char str[80];
  816.  int i;
  817.  if (bnum) {
  818.  
  819.   MouseShow(0);
  820.   strcpy(str,KeyInput("Save As < BLOB.POV >",TEXT_INPUT));
  821.   if (strlen(str) == 0) strcpy(str,"BLOB.POV");
  822.   MouseShow(1);
  823.  
  824.   fptr = fopen(str, "w+");
  825.   fprintf(fptr,"#include \"colors.inc\"\n");
  826.   fprintf(fptr,"#include \"textures.inc\"\n");
  827.   fprintf(fptr,"#include \"shapes.inc\"\n\n");
  828.   fprintf(fptr,"\ncamera {\n");
  829.   fprintf(fptr,"  location <%g, %g, %g>\n",from.x,from.y,from.z);
  830.   fprintf(fptr,"  look_at  <%g, %g, %g>\n",at.x,at.y,at.z);
  831.   fprintf(fptr,"  up       <%g, %g, %g>\n",up.x,up.y,up.z);
  832.   fprintf(fptr,"}\n\n\n");
  833.   fprintf(fptr,"light_source{< %g ,  %g ,  %g  > color White }\n\n",
  834.                                                     from.x,from.y,from.z);
  835.   fprintf(fptr,"blob  {\n");
  836.   fprintf(fptr,"  threshold %g\n",threshold);
  837.   for(i=1;i<=bnum;i++) {
  838.    if (blobs[i].radius < TOL) fprintf(fptr,"//");
  839.    fprintf(fptr, "  component  %g, %g, <%g, %g, %g>\n",  blobs[i].strength,
  840.                                                           blobs[i].radius,
  841.                                                           blobs[i].x,
  842.                                                           blobs[i].y,
  843.                                                           blobs[i].z);
  844.   }
  845.   fprintf(fptr, "\n  texture {Gold_Metal}\n}\n");
  846.   fclose(fptr);
  847.  }
  848. }
  849.  
  850. void WriteToPolyray(void)
  851. {
  852.  FILE *fptr;
  853.  char str[80];
  854.  int i;
  855.  if (bnum) {
  856.   MouseShow(0);
  857.   strcpy(str,KeyInput("Save As < BLOB.PI >",TEXT_INPUT));
  858.   if (strlen(str) == 0) strcpy(str,"BLOB.PI");
  859.   MouseShow(1);
  860.   fptr = fopen(str, "w+");
  861.   fprintf(fptr,"include \"colors.inc\"\n");
  862.   fprintf(fptr,"include \"texture.inc\"\n");
  863.   fprintf(fptr,"\nviewpoint {\n");
  864.   fprintf(fptr,"  from <%g, %g, %g>\n",from.x,from.y,from.z);
  865.   fprintf(fptr,"    at <%g, %g, %g>\n",at.x,at.y,at.z);
  866.   fprintf(fptr,"    up <%g, %g, %g>\n",up.x,up.y,up.z);
  867.   fprintf(fptr,"  angle 45\n  resolution 200,200\n  aspect 1.0\n}\n\n");
  868.   fprintf(fptr,"light <%g, %g, %g>\n\n",from.x,from.y,from.z);
  869.   fprintf(fptr,"object {\n");
  870.   fprintf(fptr,"   blob %g:\n",threshold);
  871.   for(i=1;i<=bnum;i++) {
  872.    if (blobs[i].radius < TOL) fprintf(fptr,"//");
  873.    fprintf(fptr, "   sphere  <%g, %g, %g>, %g, %g",  blobs[i].x,
  874.                                                         blobs[i].y,
  875.                                                         blobs[i].z,
  876.                                                         blobs[i].strength,
  877.                                                         blobs[i].radius);
  878.    if (i < bnum) fprintf(fptr,",\n");
  879.    else fprintf(fptr,"\n");
  880.   }
  881.   fprintf(fptr, "\n   shiny_yellow \n}\n");
  882.   fclose(fptr);
  883.  }
  884. }
  885.  
  886.  
  887. void Zoom(int mx, int my, int use_xy, int btn)
  888. {
  889.  
  890.  int i, mxold=0, myold=0, pos;
  891.  float d;
  892.  if(!use_xy) {
  893.   do {MouseXY (&mx, &my);
  894.      if((mx != mxold) || (my != myold)) {
  895.          UpdateMousePos(mx,my,0);
  896.          mxold = mx;
  897.          myold = my;
  898.       }
  899.    btn = 0;
  900.    btn = MouseClick();
  901.   }while(!btn);
  902.  }
  903.  if (btn == 1) d = 0.5;
  904.  else d = 2.0;
  905.   pos = WhereIsMouse(mx,my);
  906.    switch(pos) {
  907.     case FRONT_AREA: //Y X
  908.             World[0].Hmin *= d;
  909.                     World[0].Vmin *= d;
  910.                     World[0].Hmax *= d;
  911.                     World[0].Vmax *= d;
  912.                     break;
  913.     case SIDE_AREA: // Y Z
  914.                     World[1].Hmin *= d;
  915.                     World[1].Vmin *= d;
  916.                     World[1].Hmax *= d;
  917.                     World[1].Vmax *= d;
  918.                     break;
  919.     case TOP_AREA:  // Z X
  920.                     World[2].Hmin *= d;
  921.                     World[2].Vmin *= d;
  922.                     World[2].Hmax *= d;
  923.                     World[2].Vmax *= d;
  924.                     break;
  925.    case ISO_AREA:   // ISO
  926.                     from.x *= d;
  927.                     from.y *= d;
  928.             from.z *= d;
  929.                     break;
  930.  
  931.    }
  932.    if (pos != MENU_AREA) {
  933.      MouseShow(0);
  934.      SetWindow3D(pos,0);
  935.      clearviewport();
  936.      UpdateGridStatus(pos);
  937.      if ((pos < 3) && GridStatus) {
  938.           setcolor(LIGHTGRAY);
  939.           drawgrid(1,grid[pos]);
  940.      }
  941.      DrawAxes();
  942.      for(i=1;i<=bnum;i++) {
  943.         if (blobs[i].strength < 0) setcolor(LIGHTRED);
  944.         else setcolor(WHITE);
  945.         DrawBlobs(blobs[i],pos);
  946.      }
  947.      MouseShow(1);
  948.    }
  949.    setcolor(WHITE);
  950. }
  951. void CenterAView(int mx, int my, int use_xy, int btn)
  952. {
  953.  int i, mxold=0, myold=0, pos;
  954.  POINT3D p0, p1;
  955.  btn++; // quiet the compiler!
  956.  if(!use_xy) {
  957.    do {MouseXY (&mx, &my);
  958.      if((mx != mxold) || (my != myold)) {
  959.          UpdateMousePos(mx,my,0);
  960.          mxold = mx;
  961.          myold = my;
  962.       }
  963.    }while(!MouseClick());
  964.  }
  965.    p1 = GetPoint3D(mx,my);
  966.    pos = WhereIsMouse(mx,my);
  967.    switch(pos) {
  968.     case FRONT_AREA: //Y X
  969.                     p0.x = (World[0].Hmin + World[0].Hmax) / 2.0;
  970.                     p0.y = (World[0].Vmin + World[0].Vmax) / 2.0;
  971.                     p0.x = p1.x - p0.x;
  972.                     p0.y = p1.y - p0.y;
  973.                     World[0].Hmin += p0.x;
  974.                     World[0].Vmin += p0.y;
  975.                     World[0].Hmax += p0.x;
  976.                     World[0].Vmax += p0.y;
  977.                     break;
  978.     case SIDE_AREA: // Y Z
  979.                     p0.z = (World[1].Hmin + World[1].Hmax) / 2.0;
  980.                     p0.y = (World[1].Vmin + World[1].Vmax) / 2.0;
  981.                     p0.z = p1.z - p0.z;
  982.                     p0.y = p1.y - p0.y;
  983.                     World[1].Hmin += p0.z;
  984.                     World[1].Vmin += p0.y;
  985.                     World[1].Hmax += p0.z;
  986.                     World[1].Vmax += p0.y;
  987.                     break;
  988.     case TOP_AREA:  // Z X
  989.                     p0.x = (World[2].Hmin + World[2].Hmax) / 2.0;
  990.                     p0.z = (World[2].Vmin + World[2].Vmax) / 2.0;
  991.                     p0.x = p1.x - p0.x;
  992.                     p0.z = p1.z - p0.z;
  993.                     World[2].Hmin += p0.x;
  994.                     World[2].Vmin += p0.z;
  995.                     World[2].Hmax += p0.x;
  996.                     World[2].Vmax += p0.z;
  997.                     break;
  998.  
  999.    }
  1000.    if( (pos != MENU_AREA)) {
  1001.     MouseShow(0);
  1002.     SetWindow3D(pos,0);
  1003.     UpdateGridStatus(pos);
  1004.     clearviewport();
  1005.     if ((pos < 3) && GridStatus) {
  1006.           setcolor(LIGHTGRAY);
  1007.           drawgrid(1,grid[pos]);
  1008.     }
  1009.     DrawAxes();
  1010.     for(i=1;i<=bnum;i++) {
  1011.        if (blobs[i].strength < 0 ) setcolor(LIGHTRED);
  1012.        else setcolor(WHITE);
  1013.        DrawBlobs(blobs[i],pos);
  1014.     }
  1015.     MouseShow(1);
  1016.    }
  1017.    setcolor(WHITE);
  1018. }
  1019.  
  1020. void CreateABlob(int mx, int my, int use_xy, int btn)
  1021. {
  1022.  int i, mxold=0, myold=0, FLAG = 0;
  1023.  POINT3D p1, p2, v;
  1024.  BLOB tmp, tmpold;
  1025.  if (bnum <MAXBLOB) {
  1026.   setcolor(WHITE);
  1027.   if(!use_xy) {
  1028.    do {MouseXY (&mx, &my);
  1029.      if((mx != mxold) || (my != myold)) {
  1030.          UpdateMousePos(mx,my,0);
  1031.          mxold = mx;
  1032.          myold = my;
  1033.       }
  1034.      btn = MouseClick();
  1035.    }while(!btn);
  1036.   }
  1037.  if (btn == 1) {
  1038.   p1 = GetPoint3D(mx,my);
  1039.  
  1040.   do {MouseXY (&mx, &my);
  1041.      if((mx != mxold) || (my != myold)) {
  1042.          UpdateMousePos(mx,my,0);
  1043.          mxold = mx;
  1044.          myold = my;
  1045.      }
  1046.      p2 = GetPoint3D(mx,my);
  1047.      tmp.x = p1.x;
  1048.      tmp.y = p1.y;
  1049.      tmp.z = p1.z;
  1050.      v = subtract(&p2, &p1);
  1051.  
  1052.      tmp.strength = 1.0;
  1053.      tmp.radius = mag(&v)/sqrt(1.0 - sqrt(threshold/fabs(tmp.strength)));
  1054.  
  1055.      MouseShow(0);
  1056.      setwritemode(1);
  1057.      for(i=0;i<3;i++) { SetWindow3D(i,0); DrawBlobs(tmp,i); }
  1058.      setwritemode(0);
  1059.      MouseShow(1);
  1060.      if (!FLAG) FLAG = 1;
  1061.      else {
  1062.        MouseShow(0);
  1063.        setwritemode(1);
  1064.        for(i=0;i<3;i++) { SetWindow3D(i,0); DrawBlobs(tmpold,i); }
  1065.        setwritemode(0);
  1066.        MouseShow(1);
  1067.      }
  1068.      tmpold = tmp;
  1069.     btn = MouseClick();
  1070.   }while(!btn);
  1071.   if (btn == 1) {
  1072.    bnum++;
  1073.    blobs[bnum]  = tmp;
  1074.   }
  1075.   RedrawALL();
  1076.  } //if LMB was pressed do not create the center point!
  1077.  }// if bnum < MAXBLOB
  1078. }
  1079.  
  1080. void MoveABlob(int mx, int my, int use_xy, int btn, int copy)
  1081. {
  1082.  int i, mxold=0, myold=0,pos;
  1083.  POINT3D p2;
  1084.  BLOB tmp, tmpold;
  1085.  
  1086.  SelectABlob(mx,my,use_xy,btn);
  1087.  if (BlobSel) {
  1088.   tmp = blobs[BlobSel];
  1089.   tmpold = tmp;
  1090.   do {MouseXY (&mx, &my);}while(!MouseClick());
  1091.  
  1092.   setcolor(WHITE);
  1093.   MouseShow(0);
  1094.   for(i=0;i<4;i++) {
  1095.      SetWindow3D(i,0);
  1096.      DrawBlobs(blobs[BlobSel],i);
  1097.   }
  1098.   MouseShow(1);
  1099.   do {MouseXY (&mx, &my);
  1100.      if((mx != mxold) || (my != myold)) {
  1101.          UpdateMousePos(mx,my,0);
  1102.          mxold = mx;
  1103.          myold = my;
  1104.      }
  1105.      p2 = GetPoint3D(mx,my);
  1106.      pos = WhereIsMouse(mx,my);
  1107.      switch(pos) {
  1108.        case FRONT_AREA:  tmp.x = p2.x;  tmp.y = p2.y; break;
  1109.        case  SIDE_AREA:  tmp.y = p2.y;  tmp.z = p2.z; break;
  1110.        case   TOP_AREA:  tmp.x = p2.x;  tmp.z = p2.z; break;
  1111.      }
  1112.      MouseShow(0);
  1113.      setwritemode(1);
  1114.      setcolor(WHITE);
  1115.      for(i=0;i<3;i++) {
  1116.       SetWindow3D(i,0);
  1117.       DrawBlobs(tmpold,i);
  1118.       DrawBlobs(tmp,i);
  1119.      }
  1120.      setwritemode(0);
  1121.      MouseShow(1);
  1122.      tmpold = tmp;
  1123.    btn = MouseClick();
  1124.   }while(!btn);
  1125.  
  1126.   if (btn == 1) {
  1127.       if (!copy)  blobs[BlobSel]  = tmp;
  1128.       else {
  1129.        if (bnum < MAXBLOB) {bnum++; blobs[bnum]  = tmp;}
  1130.       }
  1131.   }
  1132.   RedrawALL();
  1133.  }
  1134. }
  1135.  
  1136. void SelectABlob(int mx, int my, int use_xy, int btn)
  1137. {
  1138.  int pos, i, mxold=0, myold=0;
  1139.  float dist, dist2, rr;
  1140.  POINT3D p1;
  1141.  
  1142.  setcolor(WHITE);
  1143.   if(!use_xy) {
  1144.    do {MouseXY (&mx, &my);
  1145.      btn = 0;
  1146.      if((mx != mxold) || (my != myold)) {
  1147.          UpdateMousePos(mx,my,0);
  1148.      mxold = mx;
  1149.      myold = my;
  1150.       }
  1151.       btn = MouseClick();
  1152.    }while(!btn);
  1153.   }
  1154.   if (btn==1) {
  1155.    p1 = GetPoint3D(mx,my);
  1156.    pos = WhereIsMouse(mx,my);
  1157.    dist = 3e30;
  1158.    BlobSel = 0;
  1159.    for(i=1;i<=bnum;i++) {
  1160.       switch(pos) {
  1161.        case FRONT_AREA:
  1162.                        dist2 = (blobs[i].x - p1.x)*(blobs[i].x - p1.x) +
  1163.                                (blobs[i].y - p1.y)*(blobs[i].y - p1.y);
  1164.                        break;
  1165.        case SIDE_AREA:
  1166.                dist2 = (blobs[i].z - p1.z)*(blobs[i].z - p1.z) +
  1167.                    (blobs[i].y - p1.y)*(blobs[i].y - p1.y);
  1168.                break;
  1169.        case TOP_AREA:
  1170.                        dist2 = (blobs[i].x - p1.x)*(blobs[i].x - p1.x) +
  1171.                                (blobs[i].z - p1.z)*(blobs[i].z - p1.z);
  1172.                        break;
  1173.        default : dist2 = 3e30; break;  //in case you select outside!
  1174.       }
  1175.  
  1176.       rr = blobs[i].radius * sqrt(1.0 - sqrt(threshold/fabs(blobs[i].strength)));
  1177.       dist2 -= rr * rr;
  1178.       dist2 = fabs(dist2);
  1179.       if (dist2 < dist) {
  1180.        dist = dist2;
  1181.        BlobSel = i;
  1182.       }
  1183.   }
  1184.  
  1185.   if (BlobSel) {
  1186.    MouseShow(0);
  1187.    for(i=0;i<4;i++) {
  1188.      SetWindow3D(i,0);
  1189.      setcolor(YELLOW);
  1190.      DrawBlobs(blobs[BlobSel],i);
  1191.      if(BlobSelOld && (BlobSelOld != BlobSel) && (BlobSelOld <= bnum)) {
  1192.       setcolor(WHITE);
  1193.       DrawBlobs(blobs[BlobSelOld],i);
  1194.      }
  1195.    }
  1196.    setcolor(WHITE);
  1197.    MouseShow(1);
  1198.    BlobSelOld = BlobSel;
  1199.   }
  1200.  }
  1201. }
  1202.  
  1203.  
  1204.  
  1205. void DrawBlobs(BLOB b, int vp)
  1206.  {
  1207.    POINT3D p;
  1208.    p.x = b.x;
  1209.    p.y = b.y;
  1210.    p.z = b.z;
  1211.  
  1212.    drawsphere (vp, p, b.radius * sqrt(1.0 - sqrt(threshold/fabs(b.strength))));
  1213.  }
  1214.  
  1215. void ExecCommand(int c, int mx, int my, int use_xy, int btnprss)
  1216. {
  1217.     FILE *fptr;
  1218.     char tfile[80], s[80];
  1219.     int i;
  1220.  
  1221.     switch(c) {
  1222.  //[0]  " Load"
  1223.      case 0: strcpy(tfile,KeyInput("Load File:",TEXT_INPUT));
  1224.              LoadAFile(tfile);
  1225.              RedrawALL();
  1226.              break;
  1227.  //[1]  " Save "
  1228.      case 1: MouseShow(0);
  1229.              sprintf(tfile,"Save As < %s >",FileName);
  1230.              strcpy(tfile,KeyInput(tfile,TEXT_INPUT));
  1231.              if (strlen(tfile) == 0) strcpy(tfile,FileName);
  1232.          MouseShow(1);
  1233.              SaveAFile(tfile);
  1234.              break;
  1235.  //[2]  " Create"
  1236.      case 2: CreateABlob(mx, my, use_xy,btnprss); break;
  1237.  //[3]  " Move"
  1238.      case 3: MoveABlob(mx, my, use_xy,btnprss,0); break;
  1239.  //[4]  " Resize"
  1240.      case 4: if (bnum) ResizeABlob(mx, my, use_xy,btnprss) ;break;
  1241.  //[5]  " Povray"
  1242.      case 5: MouseShow(0);
  1243.              WriteToPoV();
  1244.          MouseShow(1);
  1245.          break;
  1246.  //[6]  " Polyray"
  1247.      case 6: MouseShow(0);
  1248.          WriteToPolyray();
  1249.          MouseShow(1);
  1250.          break;
  1251.  //[7]  "   RAW"
  1252.      case 7:  SaveRAW = 1;
  1253.           hide_backface = 0;
  1254.           i = 1;
  1255.           MouseShow(0);
  1256.           strcpy(tfile,KeyInput("Save As < BLOB.RAW >",TEXT_INPUT));
  1257.           if (strlen(tfile) == 0) strcpy(tfile,"BLOB.RAW");
  1258.           MouseShow(1);
  1259.           sprintf(s,"Overwrite < %s > ?",tfile);
  1260.           if ((fptr = fopen(tfile,"r")) != NULL) {
  1261.          i = YesNoCMD(s);
  1262.          RedrawALL();
  1263.           }
  1264.           fclose(fptr);
  1265.           if (i) {
  1266.         fptr = fopen(tfile, "w+");   // open and close to clean up
  1267.         fclose(fptr);                // any previous data
  1268.         setcolor(WHITE);
  1269.         SetWindow3D(ISO_ID, 0);
  1270.         MouseShow(0);
  1271.         RAWfptr = fopen(tfile, "a+");
  1272.         CreateBlobs();
  1273.         fclose(RAWfptr);
  1274.         MouseShow(1);
  1275.           }
  1276.           SaveRAW = 0;
  1277.           hide_backface = 1;
  1278.           break;
  1279.  //[8]  " Zoom"
  1280.      case 8: Zoom(mx, my, use_xy,btnprss); break;
  1281.  //[9]  " Delete"
  1282.      case 9: if (bnum) DeleteBlob(mx, my, use_xy,btnprss); break;
  1283.  //[10] " Center"
  1284.      case 10: CenterAView(mx, my, use_xy,btnprss); break;
  1285.  //[11] " Camera"
  1286.      case 11: SetCamera();
  1287.           break;
  1288.  //[12] " Preview"
  1289.      case 12: if(bnum) {
  1290.            setcolor(WHITE);
  1291.            SetWindow3D(ISO_ID, 0);
  1292.            MouseShow(0);
  1293.            CreateBlobs();
  1294.            MouseShow(1);
  1295.           }
  1296.           break;
  1297.  //[13] " Strength"
  1298.      case 13: if (bnum) SetStrength(mx, my, use_xy,btnprss);
  1299.           break;
  1300.  //[14] " Quit"
  1301.      case 14: break;
  1302.  //[15] " Who"
  1303.      case 15:InfoBox("By Alfonso Hermida/Steve Anger 2/94");
  1304.          RedrawALL();
  1305.          break;
  1306. //[16] " Redraw"
  1307.      case 16: RedrawALL(); break;
  1308. //[17] " Detail"
  1309.      case 17: FULLSCREEN_VIEW
  1310.          sprintf(tfile,"Detail Level <20 - 50> [%d]",x_steps);
  1311.          strcpy(tfile,KeyInput(tfile,NUMBER_INPUT));
  1312.          if (atoi(tfile) >= 20 && atoi(tfile) <= 50)
  1313.         x_steps = y_steps = z_steps = atoi(tfile);
  1314.          break;
  1315. //[18] " New"
  1316.      case 18: if(YesNoCMD("Delete Database?")){
  1317.            bnum =0;
  1318.            strcpy(FileName,"");
  1319.           }
  1320.           RedrawALL();
  1321.           break;
  1322. //[19] " Threshold"
  1323.      case 19: FULLSCREEN_VIEW
  1324.          sprintf(tfile,"Threshold Level (>0) [%g]",threshold);
  1325.          strcpy(tfile,KeyInput(tfile,NUMBER_INPUT));
  1326.          if (strlen (tfile) && atof(tfile) >= 0) threshold = atof(tfile);
  1327.          break;
  1328. //[20] " Snap"
  1329.      case 20: FULLSCREEN_VIEW
  1330.           setcolor(15);
  1331.           setfillstyle(1,WHITE);
  1332.           bar3d(530,260,610,275,0,0);
  1333.           setcolor(0);
  1334.           if (SnapStatus)  {
  1335.          SnapStatus = 0;
  1336.          outtextxy(531, 262, "SNAP OFF");
  1337.           }
  1338.           else {
  1339.          SnapStatus = 1;
  1340.          outtextxy(531, 262,  "SNAP ON");
  1341.           }
  1342.           setcolor(WHITE);
  1343.           break;
  1344. //[21] " Grid"
  1345.      case 21: if (GridStatus) GridStatus = 0;
  1346.           else GridStatus = 1;
  1347.         RedrawALL();
  1348.           break;
  1349. //[22] "Row/Col"
  1350.      case 22: FULLSCREEN_VIEW
  1351.          sprintf(tfile,"Grid Rows/Cols (>3) [%d]",GridRowCol);
  1352.          strcpy(tfile,KeyInput(tfile,NUMBER_INPUT));
  1353.          if (strlen (tfile) && atoi(tfile) >= 3) {
  1354.          GridRowCol = atoi(tfile);
  1355.          RedrawALL();
  1356.          }
  1357.          break;
  1358. //[23] " Origin"
  1359.      case 23: do {MouseXY (&mx, &my);}while(!MouseClick());
  1360.           i = WhereIsMouse(mx,my);
  1361.           if (i >= 0 && i <= 2) {
  1362.         World[i].Hmin = -2;
  1363.         World[i].Vmin = -2;
  1364.         World[i].Hmax = 2;
  1365.         World[i].Vmax = 2;
  1366.         RedrawALL();
  1367.           }
  1368.           break;
  1369.  //[24]  " Copy"
  1370.      case 24: MoveABlob(mx, my, use_xy,btnprss,1); break;
  1371.    }
  1372. }
  1373.  
  1374. void DrawIconHiLite(Icon ic, int UpDown)
  1375. {
  1376.  MouseShow(0);
  1377.  if(UpDown == DOWN) {
  1378.   setcolor(15);
  1379.   rectangle(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+ic.height-1);
  1380.   setcolor(0);
  1381.   line(ic.x,ic.y,ic.x+ic.width,ic.y);
  1382.   line(ic.x,ic.y,ic.x,ic.y+ic.height);
  1383.   line(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+1);
  1384.   line(ic.x+1,ic.y+1,ic.x+1,ic.y+ic.height-1);
  1385.  }
  1386.  else {
  1387.   setcolor(0);
  1388.   rectangle(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+ic.height-1);
  1389.   setcolor(15);
  1390.   line(ic.x,ic.y,ic.x+ic.width,ic.y);
  1391.   line(ic.x,ic.y,ic.x,ic.y+ic.height);
  1392.   line(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+1);
  1393.   line(ic.x+1,ic.y+1,ic.x+1,ic.y+ic.height-1);
  1394.  }
  1395.   MouseShow(1);
  1396.   setcolor(WHITE);
  1397. }
  1398.  
  1399.  
  1400. POINT3D GetPoint3D(int mx, int my)
  1401. {
  1402.    POINT3D temp;
  1403.    float wx, wy;
  1404.    int k;
  1405.    k = WhereIsMouse(mx, my);
  1406.    SetWindow3D(WhereIsMouse(mx,my),0);
  1407.    switch(k) {
  1408.     case FRONT_AREA : mx = mx - 1  ; my = my - 241;     break;
  1409.     case SIDE_AREA  : mx = mx - 241; my = my - 241;   break;
  1410.     case TOP_AREA   : mx = mx - 1  ; my = my - 1;       break;
  1411.     case ISO_AREA   : mx = mx - 241; my = my - 1;     break;
  1412.    }
  1413.    if (!SnapStatus)
  1414.        ScreenToWorld(mx, my, &wx, &wy);
  1415.    else
  1416.        if (k < 3) GetGridPoint2D(grid[k],mx, my, &wx, &wy);
  1417.  
  1418.    if (fabs(wx) < TOL) wx = 0.0;
  1419.    if (fabs(wy) < TOL) wy = 0.0;
  1420.  
  1421.    switch(k) {
  1422.     case FRONT_AREA : temp.x = wx; temp.y = wy; temp.z = 0.0; break;
  1423.     case SIDE_AREA  : temp.x = 0.0; temp.y = wy; temp.z = wx; break;
  1424.     case TOP_AREA   : temp.x = wx; temp.y = 0.0; temp.z = wy; break;
  1425.     case ISO_AREA   : temp.x = wx; temp.y = wy; temp.z = 0.0; break;
  1426.    }
  1427.  
  1428.    return (temp);
  1429. }
  1430.  
  1431. void GetGridPoint2D(GRID g, int mx,int my, float * wx, float * wy)
  1432. {
  1433.  int nx,ny;
  1434.  ScreenToWorld(mx,my,wx,wy);
  1435.  nx = (*wx - g.cmin) / (float)g.colstep + .5;
  1436.  ny = (*wy - g.rmin) / (float)g.rowstep + .5;
  1437.  *wx = g.cmin + nx * g.colstep;
  1438.  *wy = g.rmin + ny * g.rowstep;
  1439. }
  1440.  
  1441. void drawgrid (int cw, GRID g)
  1442. {
  1443.    int j;
  1444.    float rmax,cmax;
  1445.    POINT3D p1,p2;
  1446.    cw++;
  1447.    setlinestyle(DOTTED_LINE,1,NORM_WIDTH);
  1448.    rmax = g.rmin+g.rowstep*(g.rows);
  1449.    cmax = g.cmin+g.colstep*(g.cols);
  1450.  
  1451.      // case = X    _|_ X axis
  1452.      //        Y    _|_ Y axis
  1453.      //        Z    _|_ Z axis
  1454.    switch(toupper(g.PerpTo))
  1455.     {
  1456.      case 'X':
  1457.          for (j=0;j<g.cols+1;j++)
  1458.           {
  1459.             p1.x = g.PlaneDist;
  1460.             p1.y = rmax;
  1461.             p1.z = g.cmin+j*g.colstep;
  1462.             p2.x = g.PlaneDist;
  1463.             p2.y = g.rmin;
  1464.             p2.z = g.cmin+j*g.colstep;
  1465.             drawline3D(&p1,&p2);
  1466.           }
  1467.          for (j=0;j<g.rows+1;j++)
  1468.       {
  1469.             p1.x = g.PlaneDist;
  1470.             p1.y = g.rmin+j*g.rowstep;
  1471.             p1.z = cmax;
  1472.             p2.x = g.PlaneDist;
  1473.             p2.y = g.rmin+j*g.rowstep;
  1474.             p2.z = g.cmin;
  1475.             drawline3D(&p1,&p2);
  1476.           }
  1477.          break;
  1478.        case 'Y':
  1479.          for (j=0;j<g.cols+1;j++)
  1480.           {
  1481.            p1.z = rmax;
  1482.            p1.y = g.PlaneDist;
  1483.            p1.x = g.cmin+j*g.colstep;
  1484.            p2.z = g.rmin;
  1485.            p2.y = g.PlaneDist;
  1486.            p2.x = g.cmin+j*g.colstep;
  1487.            drawline3D(&p1,&p2);
  1488.       }
  1489.          for (j=0;j<g.rows+1;j++)
  1490.           {
  1491.             p1.z = g.rmin+j*g.rowstep;
  1492.             p1.y = g.PlaneDist;
  1493.             p1.x = g.cmin;
  1494.             p2.z = g.rmin+j*g.rowstep;
  1495.             p2.y = g.PlaneDist;
  1496.             p2.x = cmax;
  1497.             drawline3D(&p1,&p2);
  1498.  
  1499.            }
  1500.          break;
  1501.        case 'Z':
  1502.          for (j=0;j<g.cols+1;j++)
  1503.            {
  1504.             p1.x = g.cmin+j*g.colstep;
  1505.             p1.y = rmax;
  1506.             p1.z = g.PlaneDist;
  1507.             p2.x = g.cmin+j*g.colstep;
  1508.         p2.y = g.rmin,
  1509.             p2.z = g.PlaneDist;
  1510.             drawline3D(&p1,&p2);
  1511.            }
  1512.          for (j=0;j<g.rows+1;j++)
  1513.            {
  1514.             p1.x = g.cmin;
  1515.             p1.y = g.rmin+j*g.rowstep;
  1516.             p1.z = g.PlaneDist;
  1517.             p2.x = cmax;
  1518.             p2.y = g.rmin+j*g.rowstep;
  1519.             p2.z = g.PlaneDist;
  1520.             drawline3D(&p1,&p2);
  1521.            }
  1522.          break;
  1523.     }
  1524.     setlinestyle(SOLID_LINE,1,NORM_WIDTH);
  1525. }
  1526.  
  1527.  
  1528. void UpdateMousePos(int xpos,int ypos,int status)
  1529. {
  1530.  int k;
  1531.  float wx,wy;
  1532.  char  s[80], vpl[5];
  1533.  strcpy(vpl,"");
  1534.  k = WhereIsMouse(xpos, ypos);
  1535.    switch(k) {
  1536.     case FRONT_AREA : SetWindow3D(FRONT_ID,0);
  1537.                       xpos = xpos - 1; ypos = ypos - 241;
  1538.                       strcpy(vpl,"F");
  1539.                       break;
  1540.     case SIDE_AREA  : SetWindow3D(SIDE_ID,0);
  1541.                       xpos = xpos - 241; ypos = ypos - 241;
  1542.                       strcpy(vpl,"S");
  1543.                       break;
  1544.     case TOP_AREA   : SetWindow3D(TOP_ID,0);
  1545.                       xpos = xpos - 1; ypos = ypos - 1;
  1546.                       strcpy(vpl,"T");
  1547.                       break;
  1548.     case ISO_AREA   : SetWindow3D(ISO_ID,0);
  1549.                       xpos = xpos - 241; ypos = ypos - 1;
  1550.                       strcpy(vpl,"Iso");
  1551.                       break;
  1552.     default:          SetWindow3D(FRONT_ID,0);
  1553.                       xpos = xpos - 1; ypos = ypos - 241;
  1554.                       strcpy(vpl,"M");
  1555.                       break;
  1556.    }
  1557.    FULLSCREEN_VIEW
  1558.   status++;   // keep the compiler quiet!
  1559.    if (!SnapStatus)
  1560.        ScreenToWorld(xpos, xpos, &wx, &wy);
  1561.    else
  1562.        if (k < 3)
  1563.               GetGridPoint2D(grid[k],xpos, ypos, &wx, &wy);
  1564.  
  1565.   if (fabs(wx) < TOL) wx = 0.0;
  1566.   if (fabs(wy) < TOL) wy = 0.0;
  1567.   setcolor(15);
  1568.   setfillstyle(1,WHITE);
  1569.   bar3d(490,218,getmaxx(),218+15,0,0);
  1570.   bar3d(490,218+15+5,getmaxx(),218+15+15+5,0,0);
  1571.   bar3d(490,260,515,275,0,0);
  1572.   setcolor(0);
  1573.   if (k < 3) {
  1574.    sprintf(s,"%g",wx);
  1575.    outtextxy(490+2,218+2,s);
  1576.    sprintf(s,"%g",wy);
  1577.    outtextxy(490+2,218+15+5+2,s);
  1578.   }
  1579.   outtextxy(491, 262,vpl);
  1580.   setcolor(WHITE);
  1581. }
  1582.  
  1583. int WhereIsMouse(int x, int y)
  1584. {
  1585.   // For VGA only
  1586.   if ((x > 1)   && (x < 239) && (y > 241) && (y < 478)) return FRONT_AREA;
  1587.   if ((x > 241) && (x < 478) && (y > 241) && (y < 478)) return SIDE_AREA;
  1588.   if ((x > 1)   && (x < 239) && (y >   1) && (y < 239)) return TOP_AREA;
  1589.   if ((x > 241) && (x < 478) && (y >   1) && (y < 239)) return ISO_AREA;
  1590.   return MENU_AREA;
  1591. }
  1592.  
  1593.  
  1594. void clearWindow(int vp)
  1595. {
  1596.  
  1597.  switch(vp) {
  1598.   case 0: FRONT_VIEW     break;
  1599.   case 1: SIDE_VIEW      break;
  1600.   case 2: TOP_VIEW       break;
  1601.   case 3: ISO_VIEW       break;
  1602.  }
  1603.  MouseShow(0);
  1604.  clearviewport();
  1605.  MouseShow(1);
  1606. }
  1607.  
  1608.  
  1609. void SetWindow3D(int vp, int size)
  1610. {
  1611.  ViewPort = vp;
  1612.  if (!size) {
  1613.    DeviceLeft = 1;
  1614.    DeviceTop = 1;
  1615.    DeviceRight = 238;
  1616.    DeviceBottom = 238;
  1617.  }
  1618.  else {
  1619.    DeviceLeft = 1;
  1620.    DeviceTop = 1;
  1621.    DeviceRight = getmaxy()-1;
  1622.    DeviceBottom = getmaxy()-1;
  1623.  }
  1624.  a = (DeviceRight-DeviceLeft)/2.0;
  1625.  b = DeviceLeft + a;
  1626.  c = (DeviceTop-DeviceBottom)/2.0;
  1627.  d = DeviceBottom + c;
  1628.  SetViewpoint();
  1629.  if (!size) {
  1630.     switch(vp) {
  1631.       case 0: FRONT_VIEW     break;
  1632.       case 1: SIDE_VIEW      break;
  1633.       case 2: TOP_VIEW       break;
  1634.       case 3: ISO_VIEW       break;
  1635.     }
  1636.  }
  1637.  else setviewport(1,1,getmaxy()-1,getmaxy()-1,1);
  1638. }
  1639.  
  1640.  
  1641.  
  1642. void DrawAxes(void)
  1643. {
  1644.      POINT3D v1, v2;
  1645.      setlinestyle(SOLID_LINE,1,THICK_WIDTH);
  1646.      v1.x = 0.0; v1.y = 0.0; v1.z = 0.0;
  1647.      setcolor(RED);
  1648.      v2.x = 1.0; v2.y = 0.0; v2.z = 0.0;
  1649.      drawline3D(&v1, &v2);
  1650.      setcolor(GREEN);
  1651.      v2.x = 0.0; v2.y = 1.0; v2.z = 0.0;
  1652.      drawline3D(&v1, &v2);
  1653.      setcolor(BLUE);
  1654.      v2.x = 0.0; v2.y = 0.0; v2.z = 1.0;
  1655.      drawline3D(&v1, &v2);
  1656.      setcolor(WHITE);
  1657.      setlinestyle(SOLID_LINE,1,NORM_WIDTH);
  1658. }
  1659.  
  1660.  
  1661. float DegToRad(float deg) {
  1662.   return(deg * .017453293);
  1663. }
  1664.  
  1665. float RadToDeg(float rad) {
  1666.  return(rad * 57.29577951);
  1667. }
  1668.  
  1669. void InitGraphics(void)
  1670. {
  1671.  int gdriver = VGA, gmode = VGAHI, errorcode;
  1672.  initgraph(&gdriver, &gmode, "");
  1673.  errorcode = graphresult();
  1674.  if (errorcode != grOk)  /* an error occurred */
  1675.  {
  1676.    printf("Graphics error: %s\n", grapherrormsg(errorcode));
  1677.    printf("Press any key to halt:");
  1678.    getch();
  1679.    exit(1); /* terminate with an error code */
  1680.  }
  1681.  setviewport(0,0,getmaxx(),getmaxy(),1);  /* sets viewport with line clipping */
  1682. }
  1683.  
  1684. void WorldToDevice(double xw, double yw, int *xpc, int *ypc)
  1685. {
  1686.    *xpc = (int)(a * xw + b);
  1687.    *ypc = (int)(c * yw + d);
  1688.  
  1689. }
  1690.  
  1691. void ScreenToWorld(int mx, int my, float *wx, float *wy)
  1692. {
  1693.   int v;
  1694.   v = ViewPort;
  1695.   if (ViewPort == 3) {
  1696.    *wx = (float)(mx - b)/a;
  1697.    *wy = (float)(my - d)/c;
  1698.   }
  1699.   else {
  1700.    *wx = ((1 - mx) * (World[v].Hmin-World[v].Hmax))/(float)(238-1) + World[v].Hmin ;
  1701.    *wy = ((1 - my) * (World[v].Vmax-World[v].Vmin))/(float)(238-1) + World[v].Vmax ;
  1702.   }
  1703. }
  1704.  
  1705.  
  1706. POINT3D add(POINT3D *a,POINT3D *b)
  1707. {
  1708.  POINT3D t;
  1709.  t.x = a->x + b->x;
  1710.  t.y = a->y + b->y;
  1711.  t.z = a->z + b->z;
  1712.  return(t);
  1713. }
  1714.  
  1715.  
  1716. POINT3D subtract(POINT3D *at,POINT3D *from)
  1717. {
  1718.  POINT3D t;
  1719.  t.x = at->x - from->x;
  1720.  t.y = at->y - from->y;
  1721.  t.z = at->z - from->z;
  1722.  return(t);
  1723. }
  1724.  
  1725. float mag(POINT3D *v)
  1726. {
  1727.   return sqrt(v->x * v->x + v->y * v->y + v->z * v->z);
  1728. }
  1729.  
  1730.  
  1731. int equal(POINT3D *a, POINT3D *b)
  1732. {
  1733.   return (a->x == b->x && a->y == b->y && a->z == b->z);
  1734. }
  1735.  
  1736.  
  1737. POINT3D multiply(POINT3D *v,float f)
  1738. {
  1739.  POINT3D t;
  1740.  t.x = v->x * f;
  1741.  t.y = v->y * f;
  1742.  t.z = v->z * f;
  1743.  return(t);
  1744. }
  1745.  
  1746. POINT3D divide(POINT3D *v,float d)
  1747. {
  1748.  POINT3D t;
  1749.  if (d == 0.0) {
  1750.      d = TOL;
  1751.      InfoBox("Error in DIVIDE function! Contact the authors. Save data!");
  1752.  }
  1753.  t.x = v->x / d;
  1754.  t.y = v->y / d;
  1755.  t.z = v->z / d;
  1756.  return(t);
  1757. }
  1758.  
  1759. POINT3D cross(POINT3D *v1, POINT3D *v2)
  1760. {
  1761.  POINT3D t;
  1762.  t.x = v1->y * v2->z - v2->y * v1->z;
  1763.  t.y = v1->z * v2->x - v2->z * v1->x;
  1764.  t.z = v1->x * v2->y - v2->x * v1->y;
  1765.  return(t);
  1766. }
  1767.  
  1768.  
  1769. void SetViewpoint(void)
  1770.  {
  1771.   POINT3D temp,temp2;
  1772.  
  1773.   DVal = 1.0/tan(angle/2.0);
  1774.   temp2 = subtract(&at, &from);
  1775.   a3 = divide(&temp2, mag(&temp2));
  1776.   temp = cross(&up, &temp2);
  1777.   a1 = divide(&temp, mag(&temp));
  1778.   temp = cross(&a3, &a1);
  1779.   a2 = divide(&temp, mag(&temp));
  1780.   offset_x = -a1.x * from.x - a1.y * from.y - a1.z * from.z;
  1781.   offset_y = -a2.x * from.x - a2.y * from.y - a2.z * from.z;
  1782.   offset_z = -a3.x * from.x - a3.y * from.y - a3.z * from.z;
  1783. }
  1784.  
  1785. void World2DToDevice(POINT3D pp,int *xd, int *yd)
  1786. {
  1787.  int c;
  1788.  POINT3D p;
  1789.  c = ViewPort;
  1790.  switch(c) {
  1791.   case 0: p.x = pp.x; p.y = pp.y; break;
  1792.   case 1: p.x = pp.z; p.y = pp.y; break;
  1793.   case 2: p.x = pp.x; p.y = pp.z; break;
  1794.  }
  1795.  *xd = (World[c].Hmin-p.x)*(238-1)/(World[c].Hmin-World[c].Hmax) + 1.5;
  1796.  *yd = (World[c].Vmax-p.y)*(238-1)/(World[c].Vmax-World[c].Vmin) + 1.5;
  1797. }
  1798.  
  1799. void drawline3D(POINT3D *v1, POINT3D *v2)
  1800. {
  1801.  
  1802.    float x1, y1, z1, x2, y2, z2;
  1803.    int xpc1,ypc1,xpc2,ypc2;
  1804.  
  1805.    if (ViewPort ==3) {
  1806.      x1 = (v1->x * a1.x + a1.y * v1->y + a1.z * v1->z + offset_x)*DVal;
  1807.      y1 = (v1->x * a2.x + a2.y * v1->y + a2.z * v1->z + offset_y)*DVal;
  1808.      z1 = v1->x * a3.x + a3.y * v1->y + a3.z * v1->z + offset_z;
  1809.      x2 = (v2->x * a1.x + a1.y * v2->y + a1.z * v2->z + offset_x)*DVal;
  1810.      y2 = (v2->x * a2.x + a2.y * v2->y + a2.z * v2->z + offset_y)*DVal;
  1811.      z2 = v2->x * a3.x + a3.y * v2->y + a3.z * v2->z + offset_z;
  1812.      if(z1 !=0 && z2 !=0){
  1813.        WorldToDevice(x1/z1,y1/z1,&xpc1,&ypc1);
  1814.        WorldToDevice(x2/z2,y2/z2,&xpc2,&ypc2);
  1815.      }
  1816.      else{
  1817.        WorldToDevice(x1,y1,&xpc1,&ypc1);
  1818.        WorldToDevice(x2,y2,&xpc2,&ypc2);
  1819.      }
  1820.      line(xpc1,ypc1,xpc2,ypc2);
  1821.    }
  1822.    else {
  1823.      World2DToDevice(*v1,&xpc1, &ypc1);
  1824.      World2DToDevice(*v2,&xpc2, &ypc2);
  1825.      line(xpc1,ypc1,xpc2,ypc2);
  1826.    }
  1827. }
  1828.  
  1829. void drawpoint3D(POINT3D *v1)
  1830. {
  1831.  
  1832.    float x1, y1, z1;
  1833.    int xpc1,ypc1;
  1834.   if (ViewPort ==3) {
  1835.    x1 = (v1->x * a1.x + a1.y * v1->y + a1.z * v1->z + offset_x)*DVal;
  1836.    y1 = (v1->x * a2.x + a2.y * v1->y + a2.z * v1->z + offset_y)*DVal;
  1837.    z1 = v1->x * a3.x + a3.y * v1->y + a3.z * v1->z + offset_z;
  1838.  
  1839.    if(z1 !=0 ) WorldToDevice(x1/z1,y1/z1,&xpc1,&ypc1);
  1840.    else  WorldToDevice(x1,y1,&xpc1,&ypc1);
  1841.    circle(xpc1,ypc1,5);
  1842.   }
  1843.   else {
  1844.      World2DToDevice(*v1,&xpc1, &ypc1);
  1845.      circle(xpc1,ypc1,5);
  1846.   }
  1847.  
  1848. }
  1849.  
  1850.  
  1851. void drawsphere (int WinNum, POINT3D pc,float R)
  1852. {
  1853.  POINT3D  p1,p2;
  1854.  float  v, u;
  1855.  int COUNT;
  1856. if (WinNum == 2) {
  1857.    v = 0;
  1858.    COUNT = 0;
  1859.    for(u=DegToRad(0);u<=DegToRad(360);u+=DegToRad(15)) {
  1860.      p1.x = R * cos(u);
  1861.      p1.z = R * sin(u);
  1862.      p1.y = 0;
  1863.      p1.x = pc.x + p1.x;
  1864.      p1.y = pc.y + p1.y;
  1865.      p1.z = pc.z + p1.z;
  1866.  
  1867.      if( COUNT == 0) {
  1868.     p2 = p1;
  1869.         COUNT++;
  1870.      }
  1871.      else {
  1872.         drawline3D(&p1, &p2);
  1873.         p2 = p1;
  1874.      }
  1875.  
  1876.    }
  1877. }
  1878.   if (WinNum == 0) {
  1879.    u = 0;
  1880.    COUNT = 0;
  1881.    for(v=DegToRad(0);v<=DegToRad(360);v+=DegToRad(15)) {
  1882.      p1.x = R * cos(v);
  1883.      p1.z = 0;
  1884.      p1.y = R * sin(v);
  1885.      p1.x = pc.x + p1.x;
  1886.      p1.y = pc.y + p1.y;
  1887.      p1.z = pc.z + p1.z;
  1888.  
  1889.      if( COUNT == 0) {
  1890.         p2 = p1;
  1891.         COUNT++;
  1892.      }
  1893.      else {
  1894.         drawline3D(&p1, &p2);
  1895.         p2 = p1;
  1896.      }
  1897.  
  1898.    }
  1899.   }
  1900.  if (WinNum == 1) {
  1901.    u = DegToRad(90);
  1902.    COUNT = 0;
  1903.    for(v=DegToRad(0);v<=DegToRad(360);v+=DegToRad(15)) {
  1904.      p1.x = 0;
  1905.      p1.z = R * cos(v);
  1906.      p1.y = R * sin(v);
  1907.      p1.x = pc.x + p1.x;
  1908.      p1.y = pc.y + p1.y;
  1909.      p1.z = pc.z + p1.z;
  1910.  
  1911.      if( COUNT == 0) {
  1912.         p2 = p1;
  1913.         COUNT++;
  1914.      }
  1915.      else {
  1916.         drawline3D(&p1, &p2);
  1917.         p2 = p1;
  1918.      }
  1919.  
  1920.    }
  1921.  }
  1922.  if (WinNum == 3) {
  1923.  for(v=DegToRad(-90);v<=DegToRad(90);v+=DegToRad(30)) {
  1924.    COUNT = 0;
  1925.    for(u=DegToRad(0);u<=DegToRad(360+30);u+=DegToRad(30)) {
  1926.      p1.x = R * cos(v) * cos(u);
  1927.      p1.z = R * cos(v) * sin(u);
  1928.      p1.y = R * sin(v);
  1929.      p1.x = pc.x + p1.x;
  1930.      p1.y = pc.y + p1.y;
  1931.      p1.z = pc.z + p1.z;
  1932.  
  1933.      if( COUNT == 0) {
  1934.         p2 = p1;
  1935.         COUNT++;
  1936.      }
  1937.      else {
  1938.         drawline3D(&p1, &p2);
  1939.         p2 = p1;
  1940.      }
  1941.  
  1942.    }
  1943.  }
  1944.  
  1945.  for(u=DegToRad(0);u<= DegToRad(360);u+=DegToRad(30)) {
  1946.    COUNT = 0;
  1947.    for(v=DegToRad(-90);v<=DegToRad(90+30);v+=DegToRad(30)) {
  1948.      p1.x = R * cos(v) * cos(u);
  1949.      p1.z = R * cos(v) * sin(u);
  1950.      p1.y = R * sin(v);
  1951.      p1.x = pc.x + p1.x;
  1952.      p1.y = pc.y + p1.y;
  1953.      p1.z = pc.z + p1.z;
  1954.  
  1955.      if( COUNT == 0) {
  1956.         p2 = p1;
  1957.         COUNT++;
  1958.      }
  1959.      else {
  1960.         drawline3D(&p1, &p2);
  1961.         p2 = p1;
  1962.      }
  1963.  
  1964.    }
  1965.  }
  1966.  }
  1967. }
  1968.  
  1969.  
  1970.  
  1971. int IsMouse()
  1972. {
  1973.    inregs.x.ax = 0;
  1974.    int86(0x33,&inregs,&outregs);
  1975.    return(outregs.x.ax ? outregs.x.bx : 0);
  1976. }
  1977.  
  1978.  
  1979.  
  1980. int MouseClick()
  1981. {
  1982.    int click = 0;
  1983.    inregs.x.ax = 5;
  1984.    inregs.x.bx = 1;
  1985.    int86(0x33,&inregs,&outregs);
  1986.    click = outregs.x.bx << 1;
  1987.    inregs.x.bx--;
  1988.    int86(0x33,&inregs,&outregs);
  1989.    return(click | outregs.x.bx);
  1990. }
  1991.  
  1992.  
  1993.  
  1994.  
  1995. void MouseXY(int *xpos,int *ypos)
  1996. {
  1997.    inregs.x.ax = 3;
  1998.    int86(0x33,&inregs,&outregs);
  1999.    *xpos = outregs.x.cx;
  2000.    *ypos = outregs.x.dx;
  2001. }
  2002.  
  2003. void MouseShow(int toggle)
  2004. {
  2005.    if (toggle) inregs.x.ax = 1;
  2006.    else inregs.x.ax = 2;
  2007.    int86(0x33,&inregs,&outregs);
  2008. }
  2009.  
  2010.  
  2011. Icon CreateIcon(int xo,int yo,int width,int height,int color,char * text)
  2012. {
  2013.  Icon temp;
  2014.  temp.x = xo;
  2015.  temp.y = yo;
  2016.  temp.width = width;
  2017.  temp.height = height;
  2018.  temp.color = color;
  2019.  strcpy(temp.str,text);
  2020.  return(temp);
  2021. }
  2022.  
  2023. void DrawIcon(Icon ic)
  2024. {
  2025.  int color;
  2026.  color = getcolor();
  2027.  MouseShow(0);
  2028.  setcolor(0);
  2029.  setfillstyle(1,ic.color);
  2030.  bar3d(ic.x,ic.y,ic.x+ic.width,ic.y+ic.height,0,0);
  2031.  rectangle(ic.x,ic.y,ic.x+ic.width,ic.y+ic.height);
  2032.  rectangle(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+ic.height-1);
  2033.  outtextxy(ic.x+2,ic.y + 5,ic.str);
  2034.  setcolor(15);
  2035.  line(ic.x,ic.y,ic.x+ic.width,ic.y);
  2036.  line(ic.x,ic.y,ic.x,ic.y+ic.height);
  2037.  line(ic.x+1,ic.y+1,ic.x+ic.width-1,ic.y+1);
  2038.  line(ic.x+1,ic.y+1,ic.x+1,ic.y+ic.height-1);
  2039.  outtextxy(ic.x+1,ic.y + 4,ic.str);
  2040.  MouseShow(1);
  2041.  setcolor(color);
  2042. }
  2043.  
  2044. int IconCheck(Icon ikon,int xm,int ym)
  2045. {
  2046.  if ((xm > ikon.x) && (xm < ikon.x + ikon.width) &&
  2047.      (ym > ikon.y) && (ym < ikon.y + ikon.height))
  2048.   return(1);
  2049.  else return(0);
  2050. }
  2051.  
  2052. void CreateIconColumn(int xo,int yo,int width,int height,int color,
  2053.                       int spc, int num, Icon icon[],char **text)
  2054. {
  2055.  int i,y;
  2056.  y = yo;
  2057.  for(i=0;i<num;i++) {
  2058.    icon[i] = CreateIcon(xo,y,width,height,color,text[i]);
  2059.    y += height + spc;
  2060.  }
  2061. }
  2062.  
  2063. POINTint World3DToDevice(POINT3D v1)
  2064. {
  2065.    float x1, y1, z1;
  2066.    int xpc1,ypc1;
  2067.    POINTint tmp;
  2068.   if (ViewPort ==3) {
  2069.    x1 = (v1.x * a1.x + a1.y * v1.y + a1.z * v1.z + offset_x)*DVal;
  2070.    y1 = (v1.x * a2.x + a2.y * v1.y + a2.z * v1.z + offset_y)*DVal;
  2071.    z1 = v1.x * a3.x + a3.y * v1.y + a3.z * v1.z + offset_z;
  2072.  
  2073.    if(z1 !=0 ) WorldToDevice(x1/z1,y1/z1,&xpc1,&ypc1);
  2074.    else  WorldToDevice(x1,y1,&xpc1,&ypc1);
  2075.    tmp.x = xpc1; tmp.y = ypc1; return (tmp);
  2076.   }
  2077.   else {
  2078.      World2DToDevice(v1,&xpc1, &ypc1);
  2079.      tmp.x = xpc1; tmp.y = ypc1; return (tmp);
  2080.   }
  2081.  
  2082. }
  2083.  
  2084. void drawpolygon (POINT3D *poly, int size)
  2085. {
  2086.   POINTint p[6], p12,p32;
  2087.   int i, drawit, pp[14], count;
  2088.   long sum;
  2089.  
  2090.   if (SaveRAW) {
  2091.     for (i=1;i <= size-2;i++)
  2092.       fprintf (RAWfptr,"%g %g %g %g %g %g %g %g %g\n",
  2093.                poly[0].x,poly[0].y,poly[0].z,
  2094.                poly[i].x,poly[i].y,poly[i].z,
  2095.                poly[i+1].x,poly[i+1].y,poly[i+1].z);
  2096.   }
  2097.  
  2098.   for (i = 0; i < size; i++)
  2099.      p[i] = World3DToDevice(poly[i]);
  2100.  
  2101.   for(i=0,count=0; i<2*size; i+=2,count++) {
  2102.      pp[i]   = p[count].x;
  2103.      pp[i+1] = p[count].y;
  2104.   }
  2105.  
  2106.   pp[i] = pp[0]; pp[i+1] = pp[1];
  2107.  
  2108.   if (!hide_backface)
  2109.       drawit = 1; /* Draw everything */
  2110.   else {
  2111.       /* find the "average" normal to the polygon */
  2112.       sum = 0;
  2113.       for (i = 1; i <= size-2; i++) {
  2114.          p12.x = p[i].x - p[0].x;
  2115.          p12.y = p[i].y - p[0].y;
  2116.          p32.x = p[i+1].x - p[0].x;
  2117.          p32.y = p[i+1].y - p[0].y;
  2118.  
  2119.          sum = sum + ((long)p12.x * (long)p32.y) -
  2120.                      ((long)p12.y * (long)p32.x);
  2121.       }
  2122.  
  2123.       /* Only draw the front faces */
  2124.       drawit = (sum > 0);
  2125.   }
  2126.  
  2127.   if (drawit)
  2128.       fillpoly(size,pp);
  2129. }
  2130.  
  2131.  
  2132. /* Calculates the field strength of the blob at point 'p' */
  2133. float BlobFunc (POINT3D p)
  2134. {
  2135.     POINT3D dist;
  2136.     float field, r, r2, temp;
  2137.     int i;
  2138.  
  2139.     field = 0.0;
  2140.  
  2141.     for (i = 1; i <= bnum; i++) {
  2142.         dist.x = p.x - blobs[i].x;
  2143.         dist.y = p.y - blobs[i].y;
  2144.         dist.z = p.z - blobs[i].z;
  2145.  
  2146.         r  = dist.x*dist.x + dist.y*dist.y + dist.z*dist.z;
  2147.         r2 = blobs[i].radius * blobs[i].radius;
  2148.  
  2149.         if (r < r2) {
  2150.             temp = (1.0 - r/r2);
  2151.             field += blobs[i].strength * temp*temp;
  2152.         }
  2153.     }
  2154.  
  2155.     return (field - threshold);
  2156. }
  2157.  
  2158.  
  2159. /* Allocate memory for the marching cubes algorithm */
  2160. int AllocateCubes()
  2161. {
  2162.     int i;
  2163.  
  2164.     level0 = malloc ((y_steps+1) * sizeof(SAMPLE *));
  2165.     if (level0 == NULL)
  2166.         return 0;
  2167.  
  2168.     for (i = 0; i < y_steps+1; i++) {
  2169.         level0[i] = malloc ((z_steps+1) * sizeof(SAMPLE));
  2170.         if (level0[i] == NULL)
  2171.             return 0;
  2172.     }
  2173.  
  2174.     level1 = malloc ((y_steps+1) * sizeof(SAMPLE *));
  2175.     if (level1 == NULL)
  2176.         return 0;
  2177.  
  2178.     for (i = 0; i < y_steps+1; i++) {
  2179.         level1[i] = malloc ((z_steps+1) * sizeof(SAMPLE));
  2180.         if (level1[i] == NULL)
  2181.             return 0;
  2182.     }
  2183.  
  2184.     return 1;
  2185. }
  2186.  
  2187.  
  2188. void FreeCubes()
  2189. {
  2190.     int i;
  2191.  
  2192.     for (i = 0; i < y_steps+1; i++)
  2193.         free (level0[i]);
  2194.     free (level0);
  2195.  
  2196.     for (i = 0; i < y_steps+1; i++)
  2197.         free (level1[i]);
  2198.     free (level1);
  2199. }
  2200.  
  2201.  
  2202. void SampleLevel (SAMPLE **level, int ix,
  2203.                   POINT3D *vmin, POINT3D *vmax)
  2204. {
  2205.     POINT3D v;
  2206.     int iy, iz;
  2207.  
  2208.     v.x = (float)ix/x_steps * vmin->x +
  2209.           (1.0 - (float)ix/x_steps)*vmax->x;
  2210.  
  2211.     for (iy = 0; iy <= y_steps; iy++) {
  2212.         v.y = (float)iy/y_steps * vmin->y +
  2213.               (1.0 - (float)iy/y_steps)*vmax->y;
  2214.  
  2215.         for (iz = 0; iz <= z_steps; iz++) {
  2216.             v.z =  (float)iz/z_steps * vmin->z +
  2217.                    (1.0 - (float)iz/z_steps)*vmax->z;
  2218.  
  2219.             level[iy][iz].loc   = v;
  2220.             level[iy][iz].value = BlobFunc (v);
  2221.         }
  2222.     }
  2223. }
  2224.  
  2225.  
  2226. /* Break the blob up into a mesh and display it */
  2227. int CreateBlobs()
  2228. {
  2229.     int i, ix, iy, iz;
  2230.     BLOB b;
  2231.     SAMPLE **temp;
  2232.     POINT3D vmin = {+1e30, +1e30, +1e30};
  2233.     POINT3D vmax = {-1e30, -1e30, -1e30};
  2234.  
  2235.     clearviewport();
  2236.     setfillstyle(1,7);
  2237.  
  2238.     /* Find the extents of the shape */
  2239.     for (i = 1; i <= bnum; i++) {
  2240.        b = blobs[i];
  2241.        if (b.x - b.radius < vmin.x) vmin.x = b.x - b.radius;
  2242.        if (b.x + b.radius > vmax.x) vmax.x = b.x + b.radius;
  2243.        if (b.y - b.radius < vmin.y) vmin.y = b.y - b.radius;
  2244.        if (b.y + b.radius > vmax.y) vmax.y = b.y + b.radius;
  2245.        if (b.z - b.radius < vmin.z) vmin.z = b.z - b.radius;
  2246.        if (b.z + b.radius > vmax.z) vmax.z = b.z + b.radius;
  2247.     }
  2248.  
  2249.     if (!AllocateCubes()) {
  2250.         closegraph();
  2251.         printf("Not enough memory for marching cubes.");
  2252.         exit(1);
  2253.     }
  2254.  
  2255.     SampleLevel (level0, 0, &vmin, &vmax);
  2256.  
  2257.     for (ix = 1; ix <= x_steps; ix++) {
  2258.         SampleLevel (level1, ix, &vmin, &vmax);
  2259.  
  2260.         for (iy = 0; iy < y_steps; iy++)
  2261.             for (iz = 0; iz < z_steps; iz++)
  2262.                CubeIntersect (iy, iz);
  2263.  
  2264.         temp = level0;
  2265.         level0 = level1;
  2266.         level1 = temp;
  2267.     }
  2268.  
  2269.     FreeCubes();
  2270.  
  2271.     return 1;
  2272. }
  2273.  
  2274.  
  2275. void CubeIntersect (int iy, int iz)
  2276. {
  2277.     SAMPLE  cube[8];
  2278.     int     i, j, polysize, numline;
  2279.     PAIR3D  line[12], temp;
  2280.     POINT3D poly[12];
  2281.  
  2282.     cube[0] = level0[iy][iz];
  2283.     cube[1] = level1[iy][iz];
  2284.     cube[2] = level0[iy+1][iz];
  2285.     cube[3] = level1[iy+1][iz];
  2286.     cube[4] = level0[iy][iz+1];
  2287.     cube[5] = level1[iy][iz+1];
  2288.     cube[6] = level0[iy+1][iz+1];
  2289.     cube[7] = level1[iy+1][iz+1];
  2290.  
  2291.     /* Analyze each of the 6 faces of the cube one at a time. For
  2292.        each face that was intersected save the intersection line */
  2293.  
  2294.     numline = 0;
  2295.  
  2296.     FaceIntersect (cube, 0, 1, 3, 2, line, &numline);
  2297.     FaceIntersect (cube, 4, 6, 7, 5, line, &numline);
  2298.     FaceIntersect (cube, 0, 2, 6, 4, line, &numline);
  2299.     FaceIntersect (cube, 1, 5, 7, 3, line, &numline);
  2300.     FaceIntersect (cube, 0, 4, 5, 1, line, &numline);
  2301.     FaceIntersect (cube, 2, 3, 7, 6, line, &numline);
  2302.  
  2303.     if (numline > 0) {
  2304.         /* Sort the line segments into polygons */
  2305.         polysize = 0;
  2306.  
  2307.         for (i = 0; i < numline; i++) {
  2308.         poly[polysize++] = line[i].p1;
  2309.  
  2310.             for (j = i+1; j < numline; j++) {
  2311.                 if (equal (&line[j].p1, &line[i].p2)) {
  2312.                     temp = line[j];
  2313.                     line[j] = line[i+1];
  2314.                     line[i+1] = temp;
  2315.                     break;
  2316.                 }
  2317.             }
  2318.  
  2319.             if (j >= numline) {
  2320.                 drawpolygon (poly, polysize);
  2321.                 polysize = 0;
  2322.             }
  2323.         }
  2324.     }
  2325. }
  2326.  
  2327.  
  2328. /* Analyze a cube face for blob intersections. Intersections are
  2329.    detected by looking for positive to negative field strength
  2330.    changes between adjacent corners. If an intersection is found
  2331.    then the coords of the line segment(s) are added to array line
  2332.    and *numline is increased */
  2333. void FaceIntersect (SAMPLE *cube, int a, int b, int c, int d,
  2334.                     PAIR3D *line, int *numline)
  2335. {
  2336.     POINT3D points[4], vcenter;
  2337.     float center;
  2338.     int sign[4];
  2339.     int l1, l2, l3, l4;
  2340.     int index = 0;
  2341.  
  2342.     /* Check face edge a-b */
  2343.     if (cube[a].value * cube[b].value < 0.0) {
  2344.         sign[index] = (cube[b].value >= 0.0);
  2345.         EdgeIntersect (&points[index++], &cube[a], &cube[b]);
  2346.     }
  2347.  
  2348.     /* Check face edge b-c */
  2349.     if (cube[b].value * cube[c].value < 0.0) {
  2350.         sign[index] = (cube[c].value >= 0.0);
  2351.         EdgeIntersect (&points[index++], &cube[b], &cube[c]);
  2352.     }
  2353.  
  2354.     /* Check face edge c-d */
  2355.     if (cube[c].value * cube[d].value < 0.0) {
  2356.         sign[index] = (cube[d].value >= 0.0);
  2357.         EdgeIntersect (&points[index++], &cube[c], &cube[d]);
  2358.     }
  2359.  
  2360.     /* Check face edge d-a */
  2361.     if (cube[d].value * cube[a].value < 0.0) {
  2362.         sign[index] = (cube[a].value >= 0.0);
  2363.         EdgeIntersect (&points[index++], &cube[d], &cube[a]);
  2364.     }
  2365.  
  2366.     /* One line segment */
  2367.     if (index == 2) {
  2368.     if (sign[0] > 0) {  /* Get the line direction right */
  2369.             line[*numline].p1 = points[0];
  2370.             line[*numline].p2 = points[1];
  2371.         }
  2372.         else {
  2373.             line[*numline].p1 = points[1];
  2374.             line[*numline].p2 = points[0];
  2375.         }
  2376.  
  2377.         (*numline)++;
  2378.     }
  2379.     /* Two line segments */
  2380.     else if (index == 4) {
  2381.         /* Sample the center of the face to determine which points
  2382.            to connect */
  2383.         vcenter = add (&cube[a].loc, &cube[b].loc);
  2384.         vcenter = add (&vcenter, &cube[c].loc);
  2385.         vcenter = add (&vcenter, &cube[d].loc);
  2386.         vcenter = multiply (&vcenter, 0.25);
  2387.         center = BlobFunc(vcenter);
  2388.  
  2389.         /* Does the sign of the center sample match the
  2390.            sign of the upper left corner? */
  2391.         if ((center >= 0.0) != sign[0])
  2392.             { l1 = 0; l2 = 1; l3 = 2; l4 = 3; }
  2393.         else
  2394.             { l1 = 1; l2 = 2; l3 = 3; l4 = 0; }
  2395.  
  2396.         if (sign[l1] > 0) {  /* Get the line direction right */
  2397.             line[*numline].p1 = points[l1];
  2398.             line[*numline].p2 = points[l2];
  2399.         }
  2400.         else {
  2401.             line[*numline].p1 = points[l2];
  2402.             line[*numline].p2 = points[l1];
  2403.         }
  2404.  
  2405.         (*numline)++;
  2406.  
  2407.         if (sign[l3] > 0) {
  2408.         line[*numline].p1 = points[l3];
  2409.             line[*numline].p2 = points[l4];
  2410.         }
  2411.         else {
  2412.             line[*numline].p1 = points[l4];
  2413.             line[*numline].p2 = points[l3];
  2414.         }
  2415.  
  2416.         (*numline)++;
  2417.     }
  2418. }
  2419.  
  2420.  
  2421. void EdgeIntersect (POINT3D *v, SAMPLE *a, SAMPLE *b)
  2422. {
  2423.     POINT3D vtemp;
  2424.  
  2425.     if (a->value > b->value) {
  2426.         vtemp = subtract (&a->loc, &b->loc);
  2427.         vtemp = multiply (&vtemp, a->value/(a->value - b->value));
  2428.     *v = subtract (&a->loc, &vtemp);
  2429.     }
  2430.     else {
  2431.         vtemp = subtract (&b->loc, &a->loc);
  2432.         vtemp = multiply (&vtemp, b->value/(b->value - a->value));
  2433.         *v = subtract (&b->loc, &vtemp);
  2434.     }
  2435. }
  2436.